package org.tamal.classinfo;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * The ElementValue data structure.
 * @author Tamal Kanti Nath
 */
public final class ElementValue {

    private ClassInfo cls;
    private int tag;
    private Integer constValueIndex;
    private Integer enumTypeIndex;
    private Integer enumConstIndex;
    private Integer classInfoIndex;
    private Annotation annotationValue;
    private ElementValue[] arrayValue;

    /**
     * Creates ElementValue from DataInputStream.
     * @param in the DataInputStream
     * @param cls The ClassInfo reference
     * @throws IOException exception
     * @see Attribute
     * @see ElementValuePair
     */
    ElementValue(DataInputStream in, ClassInfo cls) throws IOException {
        this.cls = cls;
        tag = in.readUnsignedByte();
        switch (tag) {
        case 'B':
        case 'C':
        case 'D':
        case 'F':
        case 'I':
        case 'J':
        case 'S':
        case 'Z':
        case 's':
            constValueIndex = in.readUnsignedShort();
            break;
        case 'e':
            enumTypeIndex = in.readUnsignedShort();
            enumConstIndex = in.readUnsignedShort();
            break;
        case 'c':
            classInfoIndex = in.readUnsignedShort();
            break;
        case '@':
            annotationValue = new Annotation(in, cls);
            break;
        case '[':
            arrayValue = new ElementValue[in.readUnsignedShort()];
            for (int i = 0; i < arrayValue.length; ++i) {
                arrayValue[i] = new ElementValue(in, cls);
            }
            break;
        default:
            throw new ClassFormatException("Invalid ElementValue tag: " + tag);
        }
    }

    /**
     * Returns tag.
     * @return the tag
     */
    public int getTag() {
        return tag;
    }

    /**
     * Returns constValue.
     * @return the constValue
     */
    public String getConstValue() {
        return cls.getPool()[constValueIndex].toString();
    }

    /**
     * Returns enumTypeIndex.
     * @return the enumTypeIndex
     */
    public String getEnumType() {
        return cls.getPool()[enumTypeIndex].toString();
    }

    /**
     * Returns enumConst.
     * @return the enumConst
     */
    public String getEnumConst() {
        return cls.getPool()[enumConstIndex].toString();
    }

    /**
     * Returns classInfo.
     * @return the classInfo
     */
    public String getClassInfo() {
        return cls.getPool()[classInfoIndex].toString();
    }

    /**
     * Returns annotationValue.
     * @return the annotationValue
     */
    public Annotation getAnnotationValue() {
        return annotationValue;
    }

    /**
     * Returns arrayValue.
     * @return the arrayValue
     */
    public ElementValue[] getArrayValue() {
        return arrayValue;
    }

    @Override
    public String toString() {
        String str;
        switch (tag) {
        case 'B':
        case 'C':
        case 'D':
        case 'F':
        case 'I':
        case 'J':
        case 'S':
        case 'Z':
        case 's':
            str = getConstValue();
            break;
        case 'e':
            str = getEnumType() + " => " + getEnumConst();
            break;
        case 'c':
            str = getClassInfo();
            break;
        case '@':
            str = annotationValue.toString();
            break;
        case '[':
            str = Arrays.toString(arrayValue);
            break;
        default:
            str = "Tag: " + tag;
        }
        return str;
    }
}
